package com.shiku.imserver.service;

import cn.xyz.commons.constants.KConstants;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.shiku.imserver.common.AbstractService;
import com.shiku.imserver.common.ImConfig;
import com.shiku.imserver.common.message.ChatMessage;
import com.shiku.imserver.common.utils.StringUtils;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RedisService extends AbstractService {
  private static Logger log = LoggerFactory.getLogger(RedisService.class);
  
  private RedissonClient redissonClient;
  
  public static final String GET_USERID_BYTOKEN = "loginToken:userId:%s";

  public static final String GET_ACCESS_TOKEN_BY_USER_ID = "loginToken:token:%s";
  
  public static final String GET_SESSION_BY_ACCESS_TOKEN = "login:%s:session";
  
  public static final String GET_USER_BY_USERID = "user:%s:data";
  
  public static final String ROOMJID_LIST = "roomJidList:%s";
  
  public static final String GET_CONFIG = "app:config";
  
  public static final String MESSAGE_CHAT = "chatMessage:%s";
  
  public static final String MESSAGE_GROUP = "groupMessage:%s";

  public static final String Will_MESSAGE ="willMsg:%s";

  public static final String MESSAGE_buffer = "MessageBuffer:%s";

  public static final String MESSAGE_SayHello = "SayHello:%s:%s";
  
  public RedissonClient getRedissonClient() {
    return this.redissonClient;
  }
  
  public boolean initialize() {
    ImConfig.RedisConfig redisConfig = IMBeanUtils.getImconfig().getRedisConfig();
    log.info("redissonSingle start ");
    try {
      Config config = new Config();
      config.setCodec((Codec)new JsonJacksonCodec());
      SingleServerConfig serverConfig = config.useSingleServer().setAddress(redisConfig.getAddress()).setDatabase(redisConfig.getDatabase());
      serverConfig.setKeepAlive(true);
      serverConfig.setPingConnectionInterval(redisConfig.getPingConnectionInterval());
      serverConfig.setPingTimeout(redisConfig.getPingTimeout());
      serverConfig.setTimeout(redisConfig.getTimeout());
      serverConfig.setConnectTimeout(redisConfig.getConnectTimeout());
      serverConfig.setConnectionMinimumIdleSize(redisConfig.getConnectionMinimumIdleSize());
      serverConfig.setConnectionPoolSize(redisConfig.getConnectionPoolSize());
      if (!StringUtils.isEmpty(redisConfig.getPassword()))
        serverConfig.setPassword(redisConfig.getPassword()); 
      this.redissonClient = Redisson.create(config);
      
      RBucket<String> bucket = this.redissonClient.getBucket(GET_CONFIG);
      String szConfig = (String)bucket.get();
      log.info("[ww]","szConfig="+szConfig);
      log.info("redissonSingle create end ");
      initConfig();
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    } 
    return true;
  }
  
  public void initConfig() {
    JSONObject config = getConfig();
    int timeout = config.getIntValue("XMPPTimeout");
    int isSaveMsg = config.getIntValue("isSaveMsg");
    int isSaveMucMsg = config.getIntValue("isSaveMucMsg");
    int isMsgSendTime = config.getIntValue("isMsgSendTime");
    int isKeyWord = config.getIntValue("isKeyWord");
    log.info("initConfig ===> " + config.toJSONString());
    if (0 == timeout)
      timeout = 180; 
    IMBeanUtils.getImconfig().setHeartbeatTimeout(((timeout + 5) * 1000));
    IMBeanUtils.getImconfig().setSaveChatMsg((1 == isSaveMsg));
    IMBeanUtils.getImconfig().setSaveMucMsg((1 == isSaveMucMsg));
    IMBeanUtils.getImconfig().setFilterKeyWord((1 == isKeyWord));
    IMBeanUtils.getBeanManager().getGroupContext().setHeartbeatTimeout(IMBeanUtils.getImconfig().getHeartbeatTimeout());
  }
  
  public JSONObject getConfig() {
    RBucket<String> bucket = this.redissonClient.getBucket(GET_CONFIG);
    String config = (String)bucket.get();
    return JSON.parseObject(config);
  }
  
  public String getAccess_token(long userId) {
    String key = String.format(GET_ACCESS_TOKEN_BY_USER_ID, new Object[] { Long.valueOf(userId) });
    RBucket<String> bucket = this.redissonClient.getBucket(key);
    return (String)bucket.get();
  }
  
  public String getUserIdByToken(String token) {
    String key = String.format(GET_USERID_BYTOKEN, new Object[] { token });
    RBucket<String> bucket = this.redissonClient.getBucket(key);
    return (String)bucket.get();
  }
  
  public List<String> queryUserRoomJidList(Integer userId) {
    String key = String.format(ROOMJID_LIST, new Object[] { userId });
    RList<String> list = this.redissonClient.getList(key);
    if (0 == list.size()) {
      List<String> roomsJidList = IMBeanUtils.getGroupRepository().queryUserRoomsJidList(userId.intValue());
      if (0 < roomsJidList.size()) {
        list.addAllAsync(roomsJidList);
        list.expire(604800L, TimeUnit.SECONDS);
      } 
      return roomsJidList;
    } 
    return list.readAll();
  }
  
  public void updateUserRoomJidList(Integer userId) {
    String key = String.format(ROOMJID_LIST, new Object[] { userId });
    RBucket<Object> bucket = this.redissonClient.getBucket(key);
    List<String> roomsJidList = IMBeanUtils.getGroupRepository().queryUserRoomsJidList(userId.intValue());
    bucket.set(roomsJidList, 604800L, TimeUnit.SECONDS);
  }
  
  public void deleteUserRoomJidList(Integer userId) {
    String key = String.format(ROOMJID_LIST, new Object[] { userId });
    RBucket<Object> bucket = this.redissonClient.getBucket(key);
    if (bucket.isExists())
      bucket.delete(); 
  }

  /**
   * 添加未收到回复消息到redis
   * @param userId
   * @param message
   */
  public void AddWillMessage(Integer userId,ChatMessage message)
  {
     String key = String.format(Will_MESSAGE, new Object[] { userId });
     RList<ChatMessage> list = this.redissonClient.getList(key);
     list.add(message);
     list.expire(KConstants.Expire.DAY1, TimeUnit.SECONDS);
  }

  /**
   * 移除收到回执消息
   * @param userId
   * @param messageId
   */
  public void removeWillMessage(Integer userId,String messageId)
  {
    String key = String.format(Will_MESSAGE, new Object[] { userId });
    RList<ChatMessage> list = this.redissonClient.getList(key);
    for (ChatMessage item : list)
    {
        if(item.getMessageHead().getMessageId().equals(messageId))
        {
          log.info("[ww]removeWillMessage=messageId="+messageId+",item.getMessageHead().getMessageId()="+item.getMessageHead().getMessageId());
          if(list.size()==1)
          {
             list.clear();
          }
          else{
            list.remove(item);
          }
            break;
        }

    }
  }

  public RList<ChatMessage> getWillMessage(Integer userId)
  {
    String key = String.format(Will_MESSAGE, new Object[] { userId });

    return this.redissonClient.getList(key);
  }

  public ChatMessage queryChatMessage(String messageId) {
    String key = String.format(MESSAGE_CHAT, new Object[] { messageId });
    RBucket<ChatMessage> bucket = this.redissonClient.getBucket(key);
    return (ChatMessage)bucket.get();
  }
  
  public void saveChatMessage(ChatMessage message) {
    String key = String.format(MESSAGE_CHAT, new Object[] { message.getMessageHead().getMessageId() });
    RBucket<ChatMessage> bucket = this.redissonClient.getBucket(key);
    bucket.setAsync(message, 3600L, TimeUnit.SECONDS);
  }



  public  boolean isExistsSayHello(String sendUserID,String tagUserID)
  {
     String key = String.format(MESSAGE_SayHello, sendUserID,tagUserID);
     RBucket<ChatMessage> bucket = this.redissonClient.getBucket(key);
    if (bucket.isExists()) {
      return true;
    }
    return  false;
  }
  public void saveSayHello(String sendUserID,String tagUserID)
  {
    String key = String.format(MESSAGE_SayHello, sendUserID,tagUserID);
    log.info("[ww]saveSayHello,key="+key);
    RBucket<String> bucket = this.redissonClient.getBucket(key);
    bucket.setAsync("sayHello", KConstants.Expire.DAY1, TimeUnit.SECONDS);
  }
  public void delSayHello(String sendUserID,String tagUserID)
  {
    String key = String.format(MESSAGE_SayHello, sendUserID,tagUserID);
    RBucket<String> bucket = this.redissonClient.getBucket(key);
    if (bucket.isExists()) {
      bucket.delete();
    }
  }
  public  boolean queryMessage(String messageId,String UserID)
  {
    String key = String.format(MESSAGE_buffer, UserID);
    RList<String> list = this.redissonClient.getList(key);
    for (String item : list)
    {
      if(item.equals(messageId))
      {
        return true;
      }
    }
    return false;
  }
  public  void SaveMessage(String messageId,String UserID)
  {
      String key = String.format(MESSAGE_buffer, UserID);
      RList<String> list = this.redissonClient.getList(key);
      list.add(messageId);
      list.expire(300, TimeUnit.SECONDS);
  }

  public ChatMessage queryGroupMessage(String messageId) {
    String key = String.format(MESSAGE_GROUP, new Object[] { messageId });
    RBucket<ChatMessage> bucket = this.redissonClient.getBucket(key);
    return (ChatMessage)bucket.get();
  }
  
  public void saveGroupMessage(ChatMessage message) {
    String key = String.format(MESSAGE_GROUP, new Object[] { message.getMessageHead().getMessageId() });
    RBucket<ChatMessage> bucket = this.redissonClient.getBucket(key);
    bucket.setAsync(message, 300L, TimeUnit.SECONDS);
  }
  public Long saveGroupMaxMsgID(ChatMessage message)
  {
	  String key = String.format("groupMaxMessageID:%s", new Object[] { message.getMessageHead().getTo() });
	  
	  RBucket<Long> bucket = this.redissonClient.getBucket(key);
	  Long maxID = 0L;
	  if (bucket.isExists()) {
		   maxID = (Long)bucket.get();
	  }
	  else {
		  maxID = (Long)IMBeanUtils.getMessageRepository().getGroupMaxID( message.getMessageHead().getTo());
	  }
	  //撤回消息不处理
	  if(message.getType() == 202)
	  {
		  return maxID;
	  }
	  maxID = maxID+1;
	 
	  bucket.setAsync(maxID, 300L, TimeUnit.SECONDS);
	  return maxID;
  }
}
